home *** CD-ROM | disk | FTP | other *** search
/ Aminet 12 / Aminet 12 (1996)(GTI - Schatztruhe)[!][Jun 1996].iso / Aminet / util / moni / top.lha / Top / top.c < prev    next >
C/C++ Source or Header  |  1996-03-30  |  23KB  |  1,293 lines

  1.  
  2. #define VERSION "2.0 "
  3.  
  4. #define EARLIEST_LIB    37    /* 2.04 and above */
  5. /* *INDENT-OFF* */
  6.  
  7. /********************************************************************
  8.  *
  9.  * Name: Top
  10.  *
  11.  *
  12.  * Function:
  13.  *
  14.  *    A program, similar to the UNIX 'top', which displays a list of
  15.  *      Tasks/Process's showing their relative CPU-usage as a percentage.
  16.  *
  17.  *
  18.  * Implemention:
  19.  *
  20.  *    It puts a wedge in front of Exec's Switch() and records the 
  21.  *    execution time of the task/process invoked.
  22.  *    
  23.  *    The display is refreshed every 5 seconds, and lists items in
  24.  *    descending order of usage, i.e. usage hogs are at the "top".
  25.  *
  26.  *    Runs on AmigaDos 2.04 and above.
  27.  *
  28.  *
  29.  *
  30.  *****  Written by Gary Duncan
  31.  *
  32.  *      57 Melbourne Hill Rd
  33.  *      Warrandyte        << bell-birds live here :-)
  34.  *      Vic 3113
  35.  *      Australia
  36.  *
  37.  * E-mail: gduncan@werple.net.au
  38.  *
  39.  *
  40.  *****  Freely distributable for non-commercial purposes.
  41.  *      Please keep this header intact.
  42.  *
  43.  *
  44.  *      Compiles under SAS 6.x
  45.  *
  46.  *      Formatted with 'indent -gnu' ; a big time-saving program.
  47.  *
  48.  *
  49.  *
  50.  * Acknowledgements:-
  51.  *
  52.  *
  53.  *      1) Gunther Nikl for explaining how Xoper does it (Thanks, Gunther)
  54.  *       ( and to Werner Gunther for writing the original Xoper)
  55.  *
  56.  *    2) Beta-testers; thanks everyone ...
  57.  * 
  58.  *========================================================================
  59.  
  60.  Timo Karjalainen    tikarjal@raita.oulu.fi 
  61.  Everett M. Greene    mojaveg@ridgecrest.ca.us
  62.  Johan Thelmin        jth@kuai.se
  63.  Andy Savage        andy@epma.demon.co.uk
  64.  Donald J. Maddox    dmaddox@scsn.net
  65.  Innovision Concepts Ltd keith@innov.demon.co.uk
  66.  Laurent Papier        papier@dpt-info.u-strasbg.fr
  67.  Infinite Dreams    rahamans@cs.man.ac.uk 
  68.  Johan Alfredsson    d95duvan@dtek.chalmers.se
  69.  Petri Nordlund        petrin@walrus.megabaud.fi
  70.  Allan Duncan        a.duncan@trl.telstra.com.au
  71.      (no relation :)
  72.  Rene Mendoza        mendoza@cmc1.coloradomtn.edu
  73.  Michal Rybaski        mryba@mcs.com
  74.  
  75.  *========================================================================
  76.  *
  77.  *    3) ... and to C= ; I used chunks of their Console handler code
  78.  *                          from the RKRM C-examples.
  79.  *
  80.  *
  81.  ********************************************************************/
  82.  
  83. /*** Function List
  84.  
  85.  
  86.   myswitch    (void)
  87.   main        (int argc, char **argv)
  88.   build_tsk    (void)
  89.   build_tsk_item    (TOP * tsk_ptr, TASK * t_ptr, int t_num, UBYTE flag)
  90.   copy_task_name    (TOP * tsk_ptr, char *ptr)
  91.   get_proc_name    (PROCESS * p_ptr)
  92.   my_qsort    (void *ptr, int no, int sz, int (*func) ())
  93.   my_cmp    (void *p1, void *p2)
  94.   open_timer    (void)
  95.   start_timer    (int secs)
  96.   deleteTimer    (TIMEREQUEST * xt_req)
  97.   open_console    (void)
  98.   con_cleanup    (void)
  99.   openConsole    (IOSTDREQ * writereq, IOSTDREQ * readreq, WINDOW * window)
  100.   closeConsole    (IOSTDREQ * writereq)
  101.   conPuts    (IOSTDREQ * writereq, UBYTE * string)
  102.   conRead    (IOSTDREQ * readreq, UBYTE * whereto, int len)
  103.   con_win_event    (void)
  104.   get_win_size    (int *x, int *y)
  105.   move_cursor    (int x, int y)
  106.   fatal_err    (char *z)
  107.   hexit        (char *ptr)
  108.   usage        (void)
  109.  
  110.  ***/
  111.  
  112. /* *INDENT-ON* */
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145. /**** ****/
  146.  
  147. #define TASK_NAME_LEN 25
  148. #define TASK_PROC_LEN 10
  149.  
  150. #define SAMPLE_SECS    5
  151.  
  152. #include "top.h"
  153.  
  154. extern __far ULONG (*oldswitch) (void);
  155. extern __far ULONG wrapper (void);
  156. void __regargs __chkabort (void);
  157. void __regargs
  158. __chkabort (void)
  159. {
  160. }
  161.  
  162. typedef struct
  163. {
  164.   int t_no;
  165.   int t_calls;
  166.   long t_eticks;
  167.   TASK *t_task;
  168.   int t_taskpri;
  169.   BOOL t_isaCLI;
  170.   char t_type;
  171.   char t_name[TASK_NAME_LEN + 1];
  172.   int t_name_len;
  173.   char t_task_proc[TASK_PROC_LEN + 1];
  174. }
  175. TOP;
  176.  
  177. #include "proto/top_protos.h"
  178.  
  179. /*
  180.  * string for AmigaDOS Version Command
  181.  */
  182. static char A_vers[] = "$VER: top\t" VERSION __AMIGADATE__;
  183.  
  184. static char *what_who = "Top (%s) - written by gduncan@werple.net.au";
  185.  
  186.  
  187. static char *hdr =
  188. {"\x1B[1\x1B[7;31;40m\
  189. NO  TYPE       NAME                     PRI   CALLS     SECS   USAGE  STATE  \
  190. \x1B[0;31;40m\n"
  191.  
  192. };
  193.  
  194.  
  195. int my_cmp (void *p1, void *p2);
  196.  
  197.  
  198.  
  199. LIBRARY *TimerBase = NULL;
  200.  
  201. static TIMEREQUEST *t_req;
  202. static MSGPORT *timerport;
  203. static ULONG e_freq;
  204.  
  205. #define NTASKS 100
  206.  
  207. int max_lines;
  208.  
  209. TOP tlist_a[NTASKS];
  210. TOP tlist_b[NTASKS];
  211.  
  212. TOP *t_cur;
  213. TOP *t_prev;
  214.  
  215. TASK *task_list[NTASKS];
  216.  
  217.  
  218. static ECLOCKVAL ecl_now;
  219. static ECLOCKVAL ecl_last;
  220.  
  221. static EXECBASE *ExecBase;
  222.  
  223. TASK *this_task;
  224. TASK *t_ptr;
  225. int last_sort_count;
  226. int this_sort_count;
  227. int sort_flag;
  228. int t_offs;
  229. ULONG delta;
  230. int task_count;
  231. int task_count_new;
  232. int task_pri = -1;
  233. ECLOCKVAL *ecv;
  234. int not_found;
  235. int eclock;
  236. char title[80];
  237. BOOL g_switch = FALSE;
  238. int sample_time = SAMPLE_SECS;
  239.  
  240. ULONG e_ticks;
  241. ULONG e_ticks_temp;
  242. ULONG e_ticks_then;
  243.  
  244. //==================================================
  245.  
  246. SCREEN scr;
  247.  
  248. NEWWINDOW nw =
  249. {
  250.   0, 0,                /* starting position (left,top) */
  251.   640, 200,            /* width, height */
  252.   (UBYTE) - 1, (UBYTE) - 1,    /* detailpen, blockpen */
  253.  
  254.   CLOSEWINDOW | NEWSIZE,    /* flags for idcmp */
  255.   WINDOWDEPTH | WINDOWSIZING |
  256.   WINDOWDRAG | WINDOWCLOSE |
  257.   SMART_REFRESH | ACTIVATE | NEWSIZE,    /* window flags */
  258.   NULL,                /* no user gadgets */
  259.   NULL,                /* no user checkmark */
  260.   title,
  261.   NULL,                /* pointer to window screen */
  262.   NULL,                /* pointer to super bitmap */
  263.   640, 50,            /* min width, height */
  264.   640, 500,            /* max width, height */
  265.   WBENCHSCREEN            /* open on workbench screen */
  266. };
  267.  
  268.  
  269. LIBRARY *IntuitionBase = NULL;
  270. WINDOW *win = NULL;
  271. IOSTDREQ *Con_writeReq = NULL;    /* I/O request block pointer */
  272. MSGPORT *Con_writePort = NULL;    /* replyport for writes      */
  273. IOSTDREQ *Con_readReq = NULL;    /* I/O request block pointer */
  274. MSGPORT *Con_readPort = NULL;    /* replyport for reads       */
  275. BOOL OpenedConsole = FALSE;
  276.  
  277.  
  278. INTUIMESSAGE *winmsg;
  279. ULONG signals;
  280. UBYTE och;
  281. BYTE oc_error;
  282.  
  283.  
  284. /*
  285.  ********************************************************-
  286.  */
  287.  
  288. /*
  289.  * SetFunc'd into Switch(); called by asm stub, wrapper()
  290.  * 
  291.  * - this is the code which accumulates task run time. 
  292.  * 
  293.  */
  294.  
  295. void __asm __saveds __interrupt
  296. myswitch (void)
  297. {
  298.   BOOL found = FALSE;
  299.  
  300.   t_offs = 0;
  301.   t_ptr = (TASK *) ExecBase->ThisTask;
  302.  
  303.   /*
  304.    * search list for this task
  305.    */
  306.   for (t_offs = 0; t_offs < task_count;)
  307.     {
  308.       if (t_cur[t_offs].t_task == t_ptr)
  309.     {
  310.       found = TRUE;
  311.       break;
  312.     }
  313.  
  314.       if (++t_offs == NTASKS)
  315.     {
  316.       ++not_found;
  317.       return;        /* too many tasks... */
  318.     }
  319.     }                /*for */
  320.   /*
  321.    * new task, add to list
  322.    */
  323.  
  324.   if (found == FALSE)
  325.     {
  326.       build_tsk_item (&t_cur[t_offs], t_ptr, t_offs);
  327.       ++task_count;
  328.     }
  329.  
  330.   /*
  331.    * increment e-ticks used for this task...
  332.    */
  333.   eclock = ReadEClock (&ecl_now);
  334.  
  335.   delta = ecl_now.ev_lo - ecl_last.ev_lo;
  336.  
  337.   t_cur[t_offs].t_eticks += delta;
  338.   t_cur[t_offs].t_calls++;
  339.  
  340.   ecl_last = ecl_now;
  341.  
  342. }
  343.  
  344. /*
  345.  ********************************************************-
  346.  */
  347.  
  348. void
  349. main (int argc, char **argv)
  350. {
  351.   int k;
  352.   ULONG wait_mask;
  353.   ULONG retval;
  354.   LONG m_timer;
  355.   LONG m_window;
  356.   LONG m_console;
  357.  
  358.   int my_notfound;
  359.   int total_ticks;
  360.   char con_buf[200];
  361.  
  362.   TOP *tp;
  363.   int time;
  364.   int usage_percent;
  365.   int usage_dot_percent;
  366.   int secs;
  367.   int msecs;
  368.   char *ptr;
  369.   char buf_usage[40];
  370.   char buf_secs[60];
  371.  
  372.  
  373.   /*
  374.    * check for -t option
  375.    */
  376.   if (argc > 1)
  377.     {
  378.       BOOL flag = FALSE;
  379.  
  380.       if (*(ptr = argv[1]) == '-')
  381.     {
  382.       if (*++ptr == 't')
  383.         {
  384.           sample_time = atoi (++ptr);
  385.           if (sample_time < 1)
  386.         {
  387.           fprintf (stderr, "Bad time value\n");
  388.         }
  389.           else
  390.         {
  391.           flag = TRUE;
  392.         }
  393.         }
  394.     }
  395.       if (flag == FALSE)
  396.     {
  397.       usage ();
  398.       exit (0);
  399.     }
  400.     }
  401.  
  402.   ExecBase = *(EXECBASE **) 4;
  403.  
  404.   this_task = (TASK *) ExecBase->ThisTask;
  405.  
  406.   sprintf (title, what_who, VERSION);
  407.  
  408.   open_timer ();
  409.  
  410.   open_console ();
  411.  
  412.   eclock = ReadEClock (&ecl_last);
  413.  
  414.   /*
  415.    * create Wait mask (timer, Console Read , and Write)
  416.    */
  417.  
  418.   m_timer = 1 << timerport->mp_SigBit;
  419.   m_console = 1 << Con_readPort->mp_SigBit;
  420.   m_window = 1 << win->UserPort->mp_SigBit;
  421.  
  422.   wait_mask = m_timer | m_console | m_window;
  423.  
  424.   e_ticks_then = start_timer (1);    /* quick start first up */
  425.  
  426.   t_cur = tlist_a;
  427.   /*
  428.    * build list of active tasks
  429.    */
  430.  
  431.   task_count = build_tsk_array (t_cur);
  432.  
  433.   for (;;)
  434.     {
  435.  
  436.       /*
  437.        * patch exec's Switch() to ours...
  438.        */
  439.  
  440.       if (g_switch != TRUE)
  441.     {
  442.       Forbid ();
  443.       {
  444.         oldswitch = (ULONG (*)(void)) SetFunction ((LIBRARY *) ExecBase,
  445.                                -54, wrapper);
  446.         g_switch = TRUE;
  447.       }
  448.       Permit ();
  449.     }
  450.  
  451.       /*
  452.        * soak up time busy waiting for signals at lowest priority...
  453.        */
  454.       for (;;)
  455.     {
  456.       task_pri = SetTaskPri (this_task, -127);
  457.       {
  458.         while ((retval = (this_task->tc_SigRecvd & wait_mask)) == 0);
  459.       }
  460.       SetTaskPri (this_task, task_pri);    /* up priority again... */
  461.  
  462.       Disable ();
  463.       {
  464.         this_task->tc_SigRecvd &= (~retval);
  465.       }
  466.       Enable ();
  467.  
  468.       if (retval & m_console)
  469.         {
  470.           /* future use ? */
  471.  
  472.           retval &= ~m_console;
  473.         }
  474.  
  475.       if (retval & m_window)
  476.         {
  477.           retval &= ~m_window;
  478.  
  479.           if (con_win_event () == TRUE)    /* window activity */
  480.         {
  481.           hexit ("");
  482.         }
  483.         }
  484.  
  485.       if ((retval & (~wait_mask)) != 0)
  486.         {
  487.           sprintf (con_buf, "Invalid signal bit (%08X)\n", retval);
  488.           hexit (con_buf);    /*invalid */
  489.         }
  490.  
  491.       if (retval & m_timer)
  492.         {
  493.           retval &= ~m_timer;
  494.           GetMsg (timerport);    /* timer */
  495.           break;        /* get out of look to print report */
  496.         }
  497.     }
  498.  
  499.       Disable ();
  500.       {
  501.     my_notfound = not_found;
  502.     not_found = 0;
  503.     total_ticks = 0;
  504.  
  505.     /*
  506.      * switch arrays
  507.      */
  508.  
  509.     if (t_cur == tlist_a)
  510.       {
  511.         t_cur = tlist_b;
  512.         t_prev = tlist_a;
  513.       }
  514.     else
  515.       {
  516.         t_cur = tlist_a;
  517.         t_prev = tlist_b;
  518.       }
  519.  
  520.     /*
  521.      * build new list of active tasks
  522.      */
  523.  
  524.     task_count_new = build_tsk_array (t_cur);
  525.       }
  526.       Enable ();
  527.  
  528.       /*
  529.        * restart timer; get actual elapsed Eticks
  530.        */
  531.       e_ticks_temp = start_timer (sample_time);
  532.       e_ticks = e_ticks_temp - e_ticks_then;
  533.       e_ticks_then = e_ticks_temp;
  534.  
  535.  
  536.       /*
  537.        * sort task list in descending order of t_eticks
  538.        */
  539.  
  540.       my_qsort (t_prev, task_count, sizeof (TOP), my_cmp);
  541.  
  542.       task_count = task_count_new;
  543.  
  544.       move_cursor (1, 1);    /* cursor to home */
  545.  
  546.       conPuts (Con_writeReq, hdr);    /* write header */
  547.  
  548.       /*
  549.        *===============================================================
  550.        *
  551.        * ! now print report, task by task ... 
  552.        *
  553.        *===============================================================
  554.        */
  555.  
  556.       for (k = 0; k < max_lines; ++k)
  557.     {
  558.       tp = &t_prev[k];
  559.  
  560.       /*
  561.        *   ignore empty slots (task has gone) 
  562.        */
  563.  
  564.       if (tp->t_task == (TASK *) 0)
  565.         continue;
  566.  
  567.       time = tp->t_eticks;
  568.  
  569.       /*
  570.        * if time = 0 , just print spaces...
  571.        */
  572.  
  573.       if (time == 0)
  574.         {
  575.           strcpy (buf_usage, "     ");
  576.           strcpy (buf_secs, "      ");    /*ss.mmm */
  577.         }
  578.       else
  579.         {
  580.           secs = time / eclock;
  581.           msecs = (time % eclock) / 1000;
  582.  
  583.           usage_dot_percent = (((time * 100) % e_ticks) * 10) / e_ticks;
  584.           usage_percent = (time * 100) / e_ticks;
  585.  
  586.           /*
  587.            * inc to avoid printing all zeros (a "white lie" :) ...
  588.            */
  589.           if ((secs + msecs) == 0)
  590.         msecs = 1;
  591.  
  592.           if ((usage_percent + usage_dot_percent) == 0)
  593.         ++usage_dot_percent;
  594.  
  595.           sprintf (buf_secs, "%2d.", secs);
  596.           sprintf (&buf_secs[3], "%03d", msecs);
  597.  
  598.           sprintf (buf_usage, "%2d.", usage_percent);
  599.           sprintf (&buf_usage[3], "%d%%", usage_dot_percent);
  600.         }
  601.  
  602.       /*
  603.        * build this tasks report line ... 
  604.        */
  605.  
  606.       sprintf (con_buf, "%2d  %s  %-23s %4d    %4d   %s   %s   %s\n",
  607.            k,
  608.            tp->t_task_proc,
  609.            tp->t_name,
  610.            tp->t_taskpri,
  611.            tp->t_calls,
  612.            buf_secs,
  613.            buf_usage,
  614.            get_state (t_cur, tp->t_task));
  615.  
  616.       /*
  617.        * ... and write it to the Console
  618.        */
  619.       conPuts (Con_writeReq, con_buf);
  620.  
  621.       total_ticks += tp->t_eticks;
  622.       tp->t_eticks = 0;
  623.       tp->t_calls = 0;
  624.     }
  625.  
  626.       /*
  627.        * erase to end of display ( ... since a task may have gone)
  628.        */
  629.       conPuts (Con_writeReq, "\x9B\x4A");
  630.  
  631.     }
  632.  
  633.   hexit ("");
  634. }
  635. /*
  636.  *********************************************************************
  637.  */
  638.  
  639. char *
  640. get_state (TOP * t_ptr, TASK * task_ptr)
  641. {
  642.   char *r_val = "<gone>";
  643.   static char buf[10];
  644.   int j = 0;
  645.   TASK *p;
  646.  
  647.   while (p = t_ptr[j].t_task)
  648.     {
  649.       if (p == task_ptr)
  650.     {
  651.       switch (p->tc_State)
  652.         {
  653.         case 2:
  654.           r_val = "run   ";
  655.           break;
  656.  
  657.         case 3:
  658.           r_val = "ready ";
  659.           break;
  660.  
  661.         case 4:
  662.           r_val = "wait  ";
  663.           break;
  664.  
  665.         default:
  666.           sprintf (buf, "%6d", p->tc_State);
  667.           r_val = buf;
  668.           break;
  669.         }
  670.     }
  671.       ++j;
  672.     }
  673.  
  674.   return (r_val);
  675.  
  676. }
  677.  
  678. /*
  679.  *********************************************************************
  680.  */
  681.  
  682. int
  683. build_tsk_array (TOP * t_ptr)
  684. {
  685.   int tsk_no;
  686.   NODE *node;
  687.  
  688.   memset (t_ptr, sizeof(t_ptr[NTASKS]), 0);
  689.  
  690.   tsk_no = 0;
  691.  
  692.   Forbid ();
  693.   {
  694.     build_tsk_item (&t_ptr[tsk_no], this_task, tsk_no);
  695.  
  696.     ++tsk_no;
  697.  
  698.     /*
  699.      * scan Wait list
  700.      */
  701.  
  702.     for (node = ExecBase->TaskWait.lh_Head;
  703.      node->ln_Succ; node = node->ln_Succ)
  704.       {
  705.     build_tsk_item (&t_ptr[tsk_no], (TASK *) node, tsk_no);
  706.  
  707.     ++tsk_no;
  708.       }
  709.  
  710.     /*
  711.      * scan Ready list
  712.      */
  713.     for (node = ExecBase->TaskReady.lh_Head;
  714.      node->ln_Succ; node = node->ln_Succ)
  715.       {
  716.     build_tsk_item (&t_ptr[tsk_no], (TASK *) node, tsk_no);
  717.  
  718.     ++tsk_no;
  719.  
  720.       }
  721.   }
  722.   Permit ();
  723.  
  724.   return (tsk_no);
  725. }
  726.  
  727. /*
  728.  *********************************************************************
  729.  */
  730. void
  731. build_tsk_item (TOP * tsk_ptr, TASK * t_ptr, int t_num)
  732. {
  733.   char cli_name[40];
  734.  
  735.   char *ptr_name = t_ptr->tc_Node.ln_Name;
  736.   PROCESS *p_ptr = (PROCESS *) t_ptr;
  737.  
  738.   tsk_ptr->t_no = t_num;
  739.   tsk_ptr->t_calls = 0;
  740.   tsk_ptr->t_eticks = 0;
  741.   tsk_ptr->t_task = t_ptr;
  742.   tsk_ptr->t_taskpri = t_ptr->tc_Node.ln_Pri;
  743.   tsk_ptr->t_type = t_ptr->tc_Node.ln_Type;
  744.   tsk_ptr->t_isaCLI = FALSE;
  745.  
  746.   ptr_name = t_ptr->tc_Node.ln_Name;
  747.   tsk_ptr->t_name_len = strlen (ptr_name);
  748.  
  749.   /*
  750.    * construct Task/Process field 
  751.    */
  752.  
  753.   if (tsk_ptr->t_type == 1)
  754.     {
  755.       /*
  756.        * its a Task...
  757.        */
  758.  
  759.       strcpy (tsk_ptr->t_task_proc, "Task     ");
  760.     }
  761.   else
  762.     {
  763.       /*
  764.        * its a Process...
  765.        */
  766.  
  767.       int pr_num = p_ptr->pr_TaskNum;
  768.  
  769.       /* 
  770.        * check if CLI...
  771.        */
  772.       if (pr_num == 0)
  773.     {
  774.       sprintf (tsk_ptr->t_task_proc, "Proc     ");
  775.     }
  776.       else
  777.     {
  778.       char *p_name;
  779.  
  780.       tsk_ptr->t_isaCLI = TRUE;
  781.       sprintf (tsk_ptr->t_task_proc, "Proc[%2d] ", pr_num);
  782.  
  783.       /*
  784.        * CLI; build command name
  785.        */
  786.       p_name = get_proc_name (p_ptr);
  787.       sprintf (cli_name, "[ %s ]", p_name);
  788.       ptr_name = cli_name;
  789.       tsk_ptr->t_name_len = strlen (p_name);
  790.     }
  791.     }
  792.   copy_task_name (tsk_ptr, ptr_name);
  793.  
  794. }
  795.  
  796. /*
  797.  *********************************************************************
  798.  */
  799. void
  800. copy_task_name (TOP * tsk_ptr, char *ptr)
  801. {
  802.   int j;
  803.  
  804.   for (j = 0; j < TASK_NAME_LEN; ++j)
  805.     {
  806.       UBYTE cc = *ptr++;
  807.  
  808.       if (cc == 0xA9)
  809.     cc = 0;
  810.  
  811.       tsk_ptr->t_name[j] = cc;
  812.  
  813.       if (cc == '\0')
  814.     break;
  815.     }
  816.   tsk_ptr->t_name[j] = '\0';
  817. }
  818.  
  819. /*
  820.  *********************************************************************
  821.  */
  822.  
  823. char *
  824. get_proc_name (PROCESS * p_ptr)
  825. {
  826.  
  827.   COMMANDLINEINTERFACE *p_cli = BADDR (p_ptr->pr_CLI);
  828.   char *ptr;
  829.   int len;
  830.  
  831.   /*
  832.    * if it's a  CLI command, use it as task name
  833.    */
  834.   if (p_cli->cli_Module != 0)
  835.     {
  836.       ptr = BADDR (p_cli->cli_CommandName);
  837.       len = *ptr++;
  838.       ptr[len] = '\0';
  839.     }
  840.   else
  841.     {
  842.       ptr = ((TASK *) p_ptr)->tc_Node.ln_Name;
  843.     }
  844.  
  845.   return (ptr);
  846. }
  847.  
  848. /*
  849.  *********************************************************************
  850.  */
  851. BOOL
  852. my_qsort (void *ptr, int no, int sz, int (*func) ())
  853. {
  854.   last_sort_count = this_sort_count;
  855.   this_sort_count = 0;
  856.  
  857.   qsort (ptr, no, sz, func);
  858.  
  859.   if (last_sort_count == this_sort_count)
  860.     return TRUE;
  861.   else
  862.     return FALSE;
  863. }
  864.  
  865. /*
  866.  *********************************************************************
  867.  */
  868.  
  869. int
  870. my_cmp (void *p1, void *p2)
  871. {
  872.   int retval;
  873.  
  874.   retval = ((TOP *) p2)->t_eticks - ((TOP *) p1)->t_eticks;
  875.   if (retval > 0)
  876.     ++this_sort_count;
  877.  
  878.   return retval;
  879. }
  880.  
  881. /*
  882.  *********************************************************************
  883.  */
  884.  
  885. void
  886. open_timer (void)
  887. {
  888.  
  889.   if ((timerport = CreatePort ("TOP", 0)) == NULL)
  890.     {
  891.       fatal_err ("Timer Port create failure\n");
  892.     }
  893.  
  894.   if ((t_req = (TIMEREQUEST *) CreateExtIO ((MSGPORT *) timerport,
  895.                         sizeof (TIMEREQUEST))) == NULL)
  896.     {
  897.       fatal_err ("Couldn't CreateExtIO in open_timer()\n");
  898.     }
  899.  
  900.   if (OpenDevice (TIMERNAME, UNIT_VBLANK, (IOREQUEST *) t_req, 0L) != 0)
  901.     {
  902.       fatal_err ("Couldn't open VBLANK Timer\n");
  903.     }
  904.  
  905.   TimerBase = (LIBRARY *) t_req->tr_node.io_Device;
  906. }
  907. /*
  908.  *********************************************************************
  909.  */
  910.  
  911. ULONG
  912. start_timer (int secs)
  913. {
  914.   ECLOCKVAL ecl;
  915.  
  916.   /*
  917.    * set up timer request
  918.    */
  919.  
  920.   t_req->tr_node.io_Message.mn_ReplyPort = timerport;
  921.   t_req->tr_node.io_Command = TR_ADDREQUEST;
  922.   t_req->tr_node.io_Flags = 0;
  923.   t_req->tr_node.io_Error = 0;
  924.   t_req->tr_time.tv_secs = secs;
  925.   t_req->tr_time.tv_micro = 0;
  926.  
  927.   SendIO ((IOREQUEST *) & t_req->tr_node);
  928.  
  929.   /*
  930.    * return current Eclock time
  931.    */
  932.   ReadEClock (&ecl);
  933.  
  934.   return (ecl.ev_lo);
  935. }
  936.  
  937. /*
  938.  *********************************************************************
  939.  */
  940. void
  941. deleteTimer (TIMEREQUEST * xt_req)
  942. {
  943.  
  944.   if (CheckIO ((IOREQUEST *) xt_req) == 0)
  945.     {
  946.       AbortIO ((IOREQUEST *) xt_req);
  947.       WaitIO ((IOREQUEST *) xt_req);
  948.     }
  949.  
  950.   CloseDevice ((IOREQUEST *) xt_req);
  951.   DeleteExtIO ((IOREQUEST *) xt_req);
  952.  
  953.   if (timerport)
  954.     DeletePort (timerport);
  955. }
  956.  
  957. /*
  958.  *********************************************************************
  959.  */
  960.  
  961. void
  962. open_console (void)
  963.  
  964. {
  965.   int x;
  966.  
  967.   if (!(IntuitionBase = OpenLibrary ("intuition.library", EARLIEST_LIB)))
  968.     {
  969.       hexit ("Can only run on AmigaDos 2.04 and above\n");
  970.     }
  971.  
  972.   /*
  973.    * calculate max number of lines 
  974.    */
  975.   if (GetScreenData (&scr, sizeof (scr), WBENCHSCREEN, NULL) == FALSE)
  976.     {
  977.       hexit ("GetScreenData() fail\n");
  978.     }
  979.   else
  980.     {
  981.       if (scr.Height >= 400)
  982.     {
  983.       max_lines = 32;
  984.       nw.Height = 400;    /* NTSC default */
  985.     }
  986.       else if (scr.Height >= 200)
  987.     {
  988.       max_lines = 14;
  989.       nw.Height = 200;
  990.     }
  991.       else
  992.     {
  993.       hexit ("Screen too small\n");
  994.     }
  995.     }
  996.   /*
  997.    * Create reply port and io block for writing to console 
  998.    */
  999.  
  1000.   if (!(Con_writePort = CreatePort ("top.console.write", 0)))
  1001.     {
  1002.       hexit ("Can't create write port\n");
  1003.     }
  1004.  
  1005.   if (!(Con_writeReq = (IOSTDREQ *)
  1006.     CreateExtIO (Con_writePort, (LONG) sizeof (IOSTDREQ))))
  1007.     {
  1008.       hexit ("Can't create write request\n");
  1009.     }
  1010.  
  1011.   /*
  1012.    * Create reply port and io block for reading from console 
  1013.    */
  1014.  
  1015.   if (!(Con_readPort = CreatePort ("top.console.read", 0)))
  1016.     {
  1017.       hexit ("Can't create read port\n");
  1018.     }
  1019.  
  1020.   if (!(Con_readReq = (IOSTDREQ *)
  1021.     CreateExtIO (Con_readPort, (LONG) sizeof (IOSTDREQ))))
  1022.     {
  1023.       hexit ("Can't create read request\n");
  1024.     }
  1025.  
  1026.   /*
  1027.    *  Open a window 
  1028.    */
  1029.  
  1030.   if (!(win = OpenWindow (&nw)))
  1031.     {
  1032.       hexit ("OpenWindow() fail\n");
  1033.     }
  1034.  
  1035.   /*
  1036.    *  Now, attach a console to the window 
  1037.    */
  1038.  
  1039.   if (oc_error = openConsole (Con_writeReq, Con_readReq, win))
  1040.     {
  1041.       hexit ("Can't open console.device\n");
  1042.     }
  1043.   else
  1044.     {
  1045.       OpenedConsole = TRUE;
  1046.     }
  1047.   /*
  1048.    *  get size of window (cols, rows) 
  1049.    */
  1050.   get_win_size (&x, &max_lines);
  1051. }
  1052. /*
  1053.  *********************************************************************
  1054.  */
  1055.  
  1056. void
  1057. con_cleanup (void)
  1058. {
  1059.   if (Con_readReq)
  1060.     {
  1061.       if (!(CheckIO ((IOREQUEST *) Con_readReq)))
  1062.     {
  1063.       AbortIO ((IOREQUEST *) Con_readReq);
  1064.  
  1065.       WaitIO ((IOREQUEST *) Con_readReq);
  1066.     }
  1067.  
  1068.     }
  1069.   if (OpenedConsole)
  1070.     closeConsole (Con_writeReq);
  1071.  
  1072.   if (win)
  1073.     CloseWindow (win);
  1074.  
  1075.   if (Con_readReq)
  1076.     DeleteExtIO ((IOREQUEST *) Con_readReq);
  1077.  
  1078.   if (Con_readPort)
  1079.     DeletePort (Con_readPort);
  1080.  
  1081.   if (Con_writeReq)
  1082.     DeleteExtIO ((IOREQUEST *) Con_writeReq);
  1083.  
  1084.   if (Con_writePort)
  1085.     DeletePort (Con_writePort);
  1086.  
  1087.   if (IntuitionBase)
  1088.     CloseLibrary (IntuitionBase);
  1089. }
  1090.  
  1091. /*
  1092.  *********************************************************************
  1093.  */
  1094.  
  1095. BYTE
  1096. openConsole (IOSTDREQ * writereq, IOSTDREQ * readreq, WINDOW * window)
  1097. {
  1098.   BYTE open_error;
  1099.  
  1100.   writereq->io_Data = (APTR) window;
  1101.   writereq->io_Length = sizeof (WINDOW);
  1102.  
  1103.   open_error = OpenDevice ("console.device", 0, (IOREQUEST *) writereq, 0);
  1104.  
  1105.   readreq->io_Device = writereq->io_Device;    /* clone required parts */
  1106.   readreq->io_Unit = writereq->io_Unit;
  1107.  
  1108.   return (open_error);
  1109. }
  1110.  
  1111. /*
  1112.  *********************************************************************
  1113.  */
  1114.  
  1115. void
  1116. closeConsole (IOSTDREQ * writereq)
  1117. {
  1118.   CloseDevice ((IOREQUEST *) writereq);
  1119. }
  1120.  
  1121. /*
  1122.  *********************************************************************
  1123.  */
  1124.  
  1125.  
  1126. /*
  1127.  * Output a NULL-terminated string of characters to a console
  1128.  */
  1129.  
  1130. void
  1131. conPuts (IOSTDREQ * writereq, UBYTE * string)
  1132. {
  1133.   writereq->io_Command = CMD_WRITE;
  1134.   writereq->io_Data = (APTR) string;
  1135.   writereq->io_Length = -1;    /* means print till terminating null */
  1136.  
  1137.   DoIO ((IOREQUEST *) writereq);
  1138. }
  1139.  
  1140. /*
  1141.  *********************************************************************
  1142.  */
  1143.  
  1144. /*
  1145.  * Queue up a read request to console, passing it pointer
  1146.  * to a buffer into which it can read the string 
  1147.  */
  1148.  
  1149. void
  1150. conRead (IOSTDREQ * readreq, UBYTE * whereto, int len)
  1151. {
  1152.  
  1153.   readreq->io_Command = CMD_READ;
  1154.   readreq->io_Data = (APTR) whereto;
  1155.   readreq->io_Length = len;
  1156.  
  1157.   DoIO ((IOREQUEST *) readreq);
  1158. }
  1159.  
  1160. /*
  1161.  *********************************************************************
  1162.  */
  1163.  
  1164. int
  1165. con_win_event (void)
  1166. {
  1167.   int flag = FALSE;
  1168.   int x;
  1169.   int class;
  1170.  
  1171.   while (winmsg = (INTUIMESSAGE *) GetMsg (win->UserPort))
  1172.     {
  1173.       class = winmsg->Class;
  1174.  
  1175.       switch (class)
  1176.     {
  1177.     case CLOSEWINDOW:
  1178.       flag = TRUE;
  1179.       break;
  1180.  
  1181.     case NEWSIZE:
  1182.       /*
  1183.        * recalculate max lines, chars in resized window 
  1184.        */
  1185.       get_win_size (&x, &max_lines);
  1186.  
  1187.       break;
  1188.  
  1189.     default:
  1190.       break;
  1191.     }
  1192.       ReplyMsg ((MESSAGE *) winmsg);
  1193.     }
  1194.  
  1195.   return (flag);
  1196. }
  1197. /*
  1198.  *********************************************************************
  1199.  */
  1200.  
  1201. void
  1202. get_win_size (int *x, int *y)
  1203. {
  1204.   char buf[12];
  1205.   /*
  1206.    * request new window size
  1207.    */
  1208.   conPuts (Con_writeReq, "\033[0 \x71");
  1209.  
  1210.   /*
  1211.    * examine response, and get x,y  (cols, rows)
  1212.    */
  1213.  
  1214.   conRead (Con_readReq, buf, sizeof (buf));
  1215.  
  1216.   *x = atoi (&buf[8]);
  1217.   *y = atoi (&buf[5]) - 2;
  1218.  
  1219. }
  1220. /*
  1221.  *********************************************************************
  1222.  */
  1223.  
  1224. void
  1225. move_cursor (int x, int y)
  1226. {
  1227.   static char buf[10];
  1228.  
  1229.   sprintf (buf, "\x9B%d;%d\x48", y, x);
  1230.  
  1231.   conPuts (Con_writeReq, buf);
  1232. }
  1233. /*
  1234.  *********************************************************************
  1235.  */
  1236.  
  1237. void
  1238. fatal_err (char *z)
  1239. {
  1240.   fprintf (stderr, "ERROR: %s\n", z);
  1241.   hexit ("");
  1242. }
  1243.  
  1244. /*
  1245.  *********************************************************************
  1246.  */
  1247.  
  1248. void
  1249. hexit (char *ptr)
  1250. {
  1251.   if (task_pri != -1)
  1252.     SetTaskPri (this_task, task_pri);
  1253.  
  1254.   if (*ptr != '\0')
  1255.     printf ("%s", ptr);
  1256.  
  1257.   /*
  1258.    * reset Switch() vector
  1259.    */
  1260.   if (g_switch == TRUE)
  1261.     {
  1262.       Forbid ();
  1263.       {
  1264.     (ULONG (*)(void)) SetFunction ((LIBRARY *) ExecBase, -54, oldswitch);
  1265.       }
  1266.       Permit ();
  1267.     }
  1268.  
  1269.   deleteTimer (t_req);
  1270.  
  1271.   con_cleanup ();
  1272.  
  1273.   exit (0);
  1274. }
  1275. /*
  1276.  *********************************************************************
  1277.  */
  1278.  
  1279. void
  1280. usage (void)
  1281. {
  1282.   fprintf (stderr, "\
  1283. top (version %s): Written by gduncan@werple.net.au\n\n\
  1284.      Prints task usage as a relative %% over sample period, which is\n\
  1285.     5 secs, or changeable via -t option.\n\
  1286. Usage:    top [-tnn]\n\
  1287. \n\
  1288.     -t  nn = sample time in secs (default = 5)\n",
  1289.  
  1290.        VERSION);
  1291.  
  1292. }
  1293.